/*
 * Copyright 2009 André Luiz Alves Moraes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * */


package org.alamoraes.sfactory;

import java.util.Hashtable;

/**
 * Define the class used to build objects
 * @author andre
 */
public class ObjectFactory {

    /**
     * Associates the target class type with the constructor
     */
    private Hashtable<Class, IObjectConstructor<? extends Object>> builders;

    /**
     * Constructor
     */
    public ObjectFactory() {
        builders = new Hashtable<Class, IObjectConstructor<? extends Object>>();
    }

    /**
     * Call the constructor of the given target class
     * @param <T> Target type
     * @param targetClass Target classs
     * @return The instance of the object
     */
    public <T extends Object> T getInstance(Class<T> targetClass) {
        IObjectConstructor<T> constructor = (IObjectConstructor<T>)builders.get(targetClass);
        return constructor.createNew();
    }

    /**
     * Register the constructor for the given class
     * @param <T> Target class type
     * @param targetClass Target Class
     * @param constructor constructor
     */
    public <T extends Object> void register(Class targetClass, IObjectConstructor<T> constructor) {
        if (builders.containsKey(targetClass))
            builders.remove(targetClass);
        builders.put(targetClass, constructor);
    }

    private static Hashtable<Object,ObjectFactory> globalFactory = new Hashtable<Object, ObjectFactory>(10,0.7f);

    /**
     * Initializes the ObjectFactory instance for the id
     * @param factoryId
     * @param factory
     */
    public static void initializeFactory(Object factoryId, ObjectFactory factory) {

        if (globalFactory.containsKey(factoryId))
            throw new IllegalStateException("The factory can be initialized only once");

        globalFactory.put(factoryId, factory);
    }

    /**
     * Initializes the default ObjectFactory instance for the id
     * @param factoryId
     */
    public static void initializeFactory(Object factoryId) {
        initializeFactory(factoryId, new ObjectFactory());
    }

    /**
     * Get the ObjectFactory associated with the id
     * @param factoryId the factory id
     * @return the object factory
     */
    public static ObjectFactory getFactory(Object factoryId) {
        if (!globalFactory.containsKey(factoryId))
            throw new IllegalStateException("The factory was not initialized");
        return globalFactory.get(factoryId);
    }
}
